package com.igoal.dao;

import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

import com.igoal.entity.DataStatus;
import com.igoal.entity.User;
import com.igoal.entity.UserFriend;
import com.igoal.web.Constants;

@Repository("userFriendDAO")
public class UserFriendDAOImpl extends GenericDaoHibernate<UserFriend, Long> implements
		UserFriendDAO {

	public UserFriendDAOImpl() {
		super(UserFriend.class);
	}

	public List<UserFriend> listAllFriends(User owner, Boolean accepted) {
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", owner));
		dc.add(Restrictions.eq("accepted", accepted));
		getByStatus(dc, DataStatus.USING);
		return findByCriteria(dc);
	}

	public List<UserFriend> listFriends(User owner, int pageNumber) {
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", owner));
		dc.add(Restrictions.eq("accepted", Boolean.TRUE));
		getByStatus(dc, DataStatus.USING);
		return findByCriteria(dc, Constants.FRIEND_PAGE_SIZE
				* (pageNumber - 1), Constants.FRIEND_PAGE_SIZE);
	}

	public List<UserFriend> listRandomFriends(User owner, Boolean accepted) {
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", owner));
		dc.add(Restrictions.eq("accepted", accepted));
		getRandomEntities(dc);
		getByStatus(dc, DataStatus.USING);
		return findByCriteria(dc, 0, 30);
	}

	public boolean isFriend(User user1, User user2) {
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", user1));
		dc.add(Restrictions.eq("from", user2));
		dc.add(Restrictions.eq("accepted", Boolean.TRUE));
		getByStatus(dc, DataStatus.USING);
		return findByCriteria(dc).size() > 0;
	}

	public UserFriend findByFromTo(User from, User to) {
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", to));
		dc.add(Restrictions.eq("from", from));
		getByStatus(dc, DataStatus.USING);

		List<UserFriend> result = findByCriteria(dc);

		// Assert: only one record if any
		if (result.size() > 0)
			return result.get(0);

		return null;
	}
	
	public int countFriends(User owner, Boolean accepted){
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", owner));
		dc.add(Restrictions.eq("accepted", accepted));
		getRandomEntities(dc);
		getByStatus(dc, DataStatus.USING);
		return countByCriteria(dc);
	}

	public boolean exists(User from, User to) {
		DetachedCriteria dc = DetachedCriteria.forClass(UserFriend.class);
		dc.add(Restrictions.eq("to", to));
		dc.add(Restrictions.eq("from", from));
		getByStatus(dc, DataStatus.USING);
		return findByCriteria(dc).size() > 0;
	}
	
	@SuppressWarnings("unchecked")
	public List<UserFriend> listPotentialFriends(User owner, int limit) {
		HibernateTemplate temp = getHibernateTemplate();
		temp.setMaxResults(limit);
		return temp.find("select lookfriend from " + UserFriend.class.getName() + 
				" lookfriend where lookfriend.from.id in (" +
				"select friendoffriend.to.id from " + UserFriend.class.getName() +
				" friendoffriend where friendoffriend.accepted ='Y' and friendoffriend.from.id in (" +
				" select friend.to.id from " + UserFriend.class.getName() +
				" friend where friend.accepted ='Y' and friend.from.id = " + owner.getId() + ")) and " +
				" lookfriend.from.id not in (select directfriend.to.id from " + UserFriend.class.getName() +
				" directfriend where directfriend.from.id = " + owner.getId() + ") and lookfriend.from.id != " + owner.getId() + " order by rand()");
	}
}
